<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script id="ColorVertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform vec2 u_PointSize;
    uniform float u_Set;

    varying float v_Set;
    void main(){
        float sizeStart = u_PointSize.x;
        float sizeEnd = u_PointSize.y;

        gl_Position = a_Position;
        gl_PointSize = u_Set * (sizeEnd - sizeStart) + sizeStart;

        v_Set = u_Set;
    }
</script>
<script id="ColorFragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform vec4 u_Color;
    uniform vec2 u_Angle;//基础角度
    uniform float u_Diff;//扩散比例
    uniform vec2 u_Opaque;//透明时间线

    varying float v_Set;

    float pi = radians(180.0);

    vec2 nodeA = vec2(0.5, 0.2);
    vec2 nodeB = vec2(0.24, 0.65);
    vec2 nodeC = vec2(0.76, 0.65);
    
    vec2 center = vec2(0.5, 0.5);

    bool inTriangle(vec2 a, vec2 b, vec2 m) {
        vec2 ab = b - a;
        vec2 am = m - a;
        if( ab.x * am.y - ab.y * am.x > 0.0){
            return false;
        }
        return true;
    }

    void rotTriangle(float angle){
        float ang = angle * pi / 180.0;
        mat4 rotM4 = mat4(
            cos(ang), sin(ang), 0.0, 0.0,
            -sin(ang), cos(ang), 0.0, 0.0,
            0.0, 0.0, 1.0, 0.0,
            0.0, 0.0, 0.0, 1.0
        );
        nodeA = vec2(vec4((nodeA - center), 0.0, 0.0) * rotM4) + center;
        nodeB = vec2(vec4((nodeB - center), 0.0, 0.0) * rotM4) + center;
        nodeC = vec2(vec4((nodeC - center), 0.0, 0.0) * rotM4) + center;
    }

    //获取两线交点
    vec2 calculateIntersection(vec2 a1, vec2 a2, vec2 b1, vec2 b2) {
        float x1 = a1.x;
        float y1 = a1.y;
        float x2 = a2.x;
        float y2 = a2.y;

        float x3 = b1.x;
        float y3 = b1.y;
        float x4 = b2.x;
        float y4 = b2.y;

        float denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
        // 直线平行，没有交点
        if (denominator == 0.0) {
            return vec2(0.0, 0.0);
        }
        float intersectionX = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denominator;
        float intersectionY = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denominator;

        return vec2(intersectionX, intersectionY);
    }

    //获取缩放的点
    vec2 getScaleNode(vec2 center, vec2 a, float scale){
        mat4 scaleM4 = mat4(
            scale, 0.0, 0.0, 0.0,
            0.0, scale, 0.0, 0.0,
            0.0, 0.0, scale, 0.0,
            0.0, 0.0, 0.0, 1.0
        );
        return vec2(vec4((a - center), 0.0, 0.0) * scaleM4) + center;
    }

    float getDiff(vec2 center, vec2 a, vec2 b, vec2 c, vec2 m, float scale){
        //到ab的交点
        vec2 cmab = calculateIntersection(center, m, a, b);
        vec2 cmbc = calculateIntersection(center, m, b, c);
        vec2 cmca = calculateIntersection(center, m, c, a);

        vec2 a2 = a;
        vec2 b2 = b;
        vec2 c2 = c;
        vec2 cmab2 = cmab;
        vec2 cmbc2 = cmbc;
        vec2 cmca2 = cmca;
        //计算小号的三角形
        if(scale < 1.0){
            a2 = getScaleNode(center, a, scale);
            b2 = getScaleNode(center, b, scale);
            c2 = getScaleNode(center, c, scale);

            cmab2 = calculateIntersection(center, m, a2, b2);
            cmbc2 = calculateIntersection(center, m, b2, c2);
            cmca2 = calculateIntersection(center, m, c2, a2);
        }else if(scale <= 0.0){
            cmab2 = vec2(0.0, 0.0);
            cmbc2 = vec2(0.0, 0.0);
            cmca2 = vec2(0.0, 0.0);
        }

        //获取最近的一条边(已经有外边到m的距离了)
        float abm = distance(cmab, m);
        float bcm = distance(cmbc, m);
        float cam = distance(cmca, m);

        float cur = abm;
        vec2 curN = cmab;
        vec2 curN2 = cmab2;
        if(cur > bcm){
            cur = bcm;
            curN = cmbc;
            curN2 = cmbc2;
        }
        if(cur > cam){
            cur = cam;
            curN = cmca;
            curN2 = cmca2;
        }

        //判断是否在diff中
        float cm = distance(center, m);
        float cn2 = distance(center, curN2);
        if(cm < cn2){
            return 1.0;//已经在中心了
        }
        return cur / (cm - cn2 + cur);
    }

    void main(){
        vec2 m = vec2(gl_PointCoord);
        vec4 color = u_Color;
        float set = v_Set;

        float angleStart = u_Angle.x;
        float angleEnd = u_Angle.y;
        //优先旋转
        rotTriangle(angleStart + set * angleEnd);

        vec2 a = nodeA;
        vec2 b = nodeB;
        vec2 c = nodeC;

        //判断是否在里面
        if(inTriangle(a,b,m) == false){
            return;
        }
        if(inTriangle(b,c,m) == false){
            return;
        }
        if(inTriangle(c,a,m) == false){
            return;
        }

        //在里面
        color.a = getDiff(center, a, b, c, m, u_Diff);

        float opStart = u_Opaque.x;
        float opEnd = u_Opaque.y;
        if(set <= opStart){
            color.a *= 1.0 - (opStart - set) / opStart;
        }
        if(set >= opEnd){
            color.a *= 1.0 - (set - opEnd) / (1.0 - opEnd);
        }

        gl_FragColor = color;
    }
</script>
<script type="module">
    import { Matrix4, Vector3, Color, OrthographicCamera, PerspectiveCamera, Spherical } from '../js/three.module.js';
    import { CreateProgram, imgPromise } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';
    import CameraController from '../js/CameraController.js'
    import Poly from '../js/Poly4.js'
    import Control from '../js/Control.js'

    import Geo from '../js/Poly2/Geo.js'
    import Mat from '../js/Poly2/Mat.js'
    import Obj3D from '../js/Poly2/Obj3D.js'
    import Scene from '../js/Poly2/Scene.js'



    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 4;

    const gl = canvas.getContext("webgl", { antialias: true, });

    // gl.enable(gl.DEPTH_TEST);//开始背景遮挡会频闪
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);//去图片描边
    //#endregion



    const scene = new Scene({ gl: gl });
    scene.regProgram('color', {
        program: CreateProgram(gl,
            document.querySelector('#ColorVertexShader').innerText,
            document.querySelector('#ColorFragmentShader').innerText),
        attribs: ['a_Position'],
        uniforms: ['u_Opaque', 'u_PointSize', 'u_Angle',
            'u_Color', 'u_Set', 'u_Diff']
    })

    //三角形
    const triangleConfig = {
        color: [1, 1, 1, 1],

        u_Angle: [Math.random() * 360, Math.random() * 30 * -1],//角度
        u_PointSize: [100, 200],//大小
        u_Opaque: [0.3, 0.5],//透明
        u_Diff: 0.8,//扩散百分比
    };

    //main
    createParticle(2);

    //创建粒子
    function createParticle(count) {
        let particle = new Obj3D();
        for (let i = 0; i < count; i++) {
            particle.add(gl, createTriangle());
        }
        scene.add(particle);
    }

    function createTriangle() {
        const angles = [Math.random() * 360, Math.random() * 70 * -1];
        const size = [20, Math.random() * 30 + 20];

        const configTriangle1 = {
            u_Angle: angles,
            u_PointSize: size,
            u_Opaque: [0.3, 0.5],
            u_Diff: 0.8,
            color: [1, 1, 1, 1],
        };

        const configTriangle2 = {
            u_Angle: angles,
            u_PointSize: size,
            u_Opaque: [0.3, 0.5],
            u_Diff: 0.9,
            color: [0, 1, 1, 1],
        };

        const objW = create(configTriangle1);
        const objB = create(configTriangle2);
        objW.add(gl, objB);

        return objW;
    }

    function create(config) {
        const { u_PointSize, color,
            u_Angle, u_Diff, u_Opaque } = config;
        return new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 2, array: new Float32Array([0, 0]) },
                }
            }),
            mat: new Mat({
                program: 'color',
                mode: ['POINTS'],
                data: {
                    'u_Color': { type: 'uniform4fv', value: color },
                    'u_PointSize': { type: 'uniform2fv', value: u_PointSize },
                    'u_Angle': { type: 'uniform2fv', value: u_Angle },
                    'u_Opaque': { type: 'uniform2fv', value: u_Opaque },
                    'u_Set': { type: 'uniform1f', value: 0 },
                    'u_Diff': { type: 'uniform1f', value: u_Diff },
                },
            }),
        });
    }


    let set = 0;
    (function ani() {
        set += 0.01;



        if (set > 1) {
            set = -1;
        }

        if (set >= 0 && set < 1) {
            scene.children[0].setUniform('u_Set', { value: set });
        }


        draw();
        requestAnimationFrame(ani);
    })();

    function draw() {
        scene.draw();
    }

</script>

</html>